package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author zjr
 * @since 2024-12-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final IInteractionReplyService replyService;
    private final UserClient userClient;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final CategoryCache categoryCache;

    @Override
    public void saveQuestion(QuestionFormDTO dto) {
        // 1. 获取当前登录用户id
        Long userId = UserContext.getUser();
        // 2. dto转po
        InteractionQuestion question = BeanUtils.copyBean(dto, InteractionQuestion.class);
        question.setUserId(userId);
        // 3. 保存
        this.save(question);
    }

    @Override
    public void updateQuestion(Long id, QuestionFormDTO dto) {
        // 1. 校验
        if(StringUtils.isBlank(dto.getTitle()) || StringUtils.isBlank(dto.getDescription()) || dto.getAnonymity() == null){
            throw new BadRequestException("非法参数");
        }
        // 2. 校验id
        InteractionQuestion question = this.getById(id);
        if(question == null){
            throw new BadRequestException("非法参数");
        }
        // 修改只能修改自己的互动问题
        Long userId = UserContext.getUser();
        if(!userId.equals(question.getUserId())){
            throw new BadRequestException("不能修改别人的互动问题");
        }
        // 2. dto转po
        question.setTitle(dto.getTitle());
        question.setDescription(dto.getDescription());
        question.setAnonymity(dto.getAnonymity());
        this.updateById(question);
    }

    /**
     * 分页查询互动问题-用户端
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
        // 1. 校验 参数courseId
        if(query.getCourseId() == null){
            throw new BadRequestException("课程id不能为空");
        }
        // 2. 获取当前登录用户
        Long userId = UserContext.getUser();
        // 3. 分页查询互动问题 interaction_question 条件：courseId  onlyMine为true才会加userId  小节id不为空  hidden为false 分页查询 按提问时间倒序
        Page<InteractionQuestion> page = this.lambdaQuery()
//                .select(InteractionQuestion.class, new Predicate<TableFieldInfo>() {
//                    @Override
//                    public boolean test(TableFieldInfo tableFieldInfo) {
//                        // tableFieldInfo.getProperty() 用于获取InteractionQuestion实体类的属性名称
//                        return !tableFieldInfo.getProperty().equals("description");  // 指定不查询的字段
//                    }
//                })
                .select(InteractionQuestion.class, tableFieldInfo -> !tableFieldInfo.getProperty().equals("description"))
                .eq(InteractionQuestion::getCourseId, query.getCourseId())
                .eq(query.getOnlyMine(), InteractionQuestion::getUserId, userId)
                .eq(query.getSectionId() != null, InteractionQuestion::getSectionId, query.getSectionId())
                .eq(InteractionQuestion::getHidden, false)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }

        // 获取互动问题的最新回答id集合
        Set<Long> latestAnswerIds = records.stream()
                .filter(c -> c.getLatestAnswerId() != null)  // 过滤空id
                .map(InteractionQuestion::getLatestAnswerId)
                .collect(Collectors.toSet());
        Set<Long> userIds = records.stream()
                .filter(c -> c.getAnonymity() != null)   // 用户匿名提问，无需获取用户昵称显示
                .map(InteractionQuestion::getUserId)
                .collect(Collectors.toSet()); // 互动问题的用户id集合

        // 4. 根据最新回答id 批量查询回答信息 Interaction_reply 条件 in id集合
        Map<Long, InteractionReply> replyMap = new HashMap<>();
        if(CollUtils.isNotEmpty(latestAnswerIds)){
            List<InteractionReply> replyList = replyService.list(Wrappers.<InteractionReply>lambdaQuery()
                    .in(InteractionReply::getId, latestAnswerIds)
                    .eq(InteractionReply::getHidden, false));
            for (InteractionReply reply : replyList) {
                if(!reply.getAnonymity()) {
                    userIds.add(reply.getUserId());  // 将最新回答的用户id 存入userIds
                }
                replyMap.put(reply.getId(), reply);
            }
        }
        // 5. 远程调用用户服务  获取用户信息  批量
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));
        // 6. 封装vo返回
        List<QuestionVO> questionVOList = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionVO questionVO = BeanUtils.copyBean(record, QuestionVO.class);
            if(!questionVO.getAnonymity()){  // 不是匿名的情况下才赋值
                UserDTO userDTO = userDTOMap.get(record.getUserId());
                if(userDTO != null) {
                    questionVO.setUserName(userDTO.getName()); // 提问者昵称
                    questionVO.setUserIcon(userDTO.getIcon()); // 提问者头像
                }
            }
            InteractionReply reply = replyMap.get(record.getLatestAnswerId());
            if(reply != null) {
                if(!reply.getAnonymity()){ // 最新回答如果是非匿名，才设置最新回答者的昵称
                    UserDTO userDTO = userDTOMap.get(reply.getUserId());
                    if(userDTO != null){
                        questionVO.setLatestReplyUser(userDTO.getName());  // 最新的回答者昵称
                    }
                }
                questionVO.setLatestReplyContent(reply.getContent()); // 最新的回答信息
            }

            questionVOList.add(questionVO);
        }
        return PageDTO.of(page, questionVOList);
    }

    /**
     * 根据id查询问题详情-用户端
     * @param id
     * @return
     */
    @Override
    public QuestionVO queryQuestionById(Long id) {
        // 1. 校验
        if(id == null){
            throw new BadRequestException("非法参数");
        }
        // 2. 查询互动问题表 按住键查询
        InteractionQuestion question = this.getById(id);
        if(question == null){
            throw new BadRequestException("问题不存在");
        }
        // 3. 如果该问题管理员设置了隐藏，返回空
        if(question.getHidden()){
            return null;
        }
        // 4. 封装vo返回
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);
        // 5. 如果用户是匿名提问，不用查询提问者昵称和头像
        if(!question.getAnonymity()){
            // 调用用户服务
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            if(userDTO != null){
                questionVO.setUserName(userDTO.getName());
                questionVO.setUserIcon(userDTO.getIcon());
            }
        }
        return questionVO;
    }

    /**
     * 分页查询问题列表-管理端
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> queryQuestionAdminVOPage(QuestionAdminPageQuery query) {
        // 0. 如果用户传了课程的名称参数，则从es中获取名称对应的课程id
        String courseName = query.getCourseName();
        List<Long> courseIds = new ArrayList<>();
        if(StringUtils.isNotBlank(courseName)){
            courseIds = searchClient.queryCoursesIdByName(courseName); // 通过feign远程调用搜索服务，从es中搜索该关键字对应的课程id
            if(CollUtils.isEmpty(courseIds)){
                return PageDTO.empty(0L, 0L);
            }
        }
        // 1. 查询互动问题表 条件 前端传条件了就添加条件 分页 排序按提问时间倒序  管理员无需考虑hidden字段
        Page<InteractionQuestion> page = this.lambdaQuery()
                .in(CollUtils.isNotEmpty(courseIds), InteractionQuestion::getCourseId, courseIds)
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
                .between(query.getBeginTime() != null && query.getEndTime() != null,
                        InteractionQuestion::getCreateTime, query.getBeginTime(), query.getEndTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(0L, 0L);
        }
        Set<Long> uids = new HashSet<>();  // 用户id集合
        Set<Long> cids = new HashSet<>();  // 课程id集合
        Set<Long> chapterAndSectionIds = new HashSet<>(); // 章和节的id集合
        for (InteractionQuestion record : records) {
            uids.add(record.getUserId());
            cids.add(record.getCourseId());
            chapterAndSectionIds.add(record.getChapterId()); // 章id
            chapterAndSectionIds.add(record.getSectionId()); // 节id
        }
        // 2. 远程调用用户服务，获取用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(uids);
        if(CollUtils.isEmpty(userDTOS)){
            throw new BizIllegalException("用户不存在");
        }
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));

        // 3. 远程调用课程服务，获取课程信息
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(courseIds);
        if(CollUtils.isEmpty(cinfos)){
            throw new BizIllegalException("课程不存在");
        }
        Map<Long, CourseSimpleInfoDTO> cinfoMap = cinfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        // 4. 远程调用课程服务，获取章节信息
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(chapterAndSectionIds);
        if(CollUtils.isEmpty(cataSimpleInfoDTOS)){
            throw new BizIllegalException("章节信息不存在");
        }
        Map<Long, String> cataInfoMap = cataSimpleInfoDTOS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));

        // 封装vo返回
        List<QuestionAdminVO> voList= new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionAdminVO adminVO = BeanUtils.copyBean(record, QuestionAdminVO.class);
            UserDTO userDTO = userDTOMap.get(record.getUserId());
            if(userDTO != null){
                adminVO.setUserName(userDTO.getName());
            }
            CourseSimpleInfoDTO cinfoDTO = cinfoMap.get(record.getCourseId());
            if(cinfoDTO != null) {
                adminVO.setCourseName(cinfoDTO.getName());
                List<Long> categoryIds = cinfoDTO.getCategoryIds(); // 一二三级分类集合
                // 获取课程一二三级分类id
                String categoryNames = categoryCache.getCategoryNames(categoryIds);
                adminVO.setCategoryName(categoryNames); // 三级分类名称，拼接字段
            }
            adminVO.setChapterName(cataInfoMap.get(record.getChapterId()));  // 章名称
            adminVO.setSectionName(cataInfoMap.get(record.getSectionId()));  // 节名称

            voList.add(adminVO);
        }
        return PageDTO.of(page, voList);
    }
}
